package com.db.utils;

import android.text.TextUtils;
import cn.hutool.json.JSONUtil;
import com.db.main.Constant;
import com.db.utils.okhttp.HttpClientUtil;
import com.google.gson.Gson;
import org.apache.http.ConnectionClosedException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.util.HashMap;
import java.util.Map;

public class ProxyUtil {

    private String mcc;
    private String mnc;
    private String language;
    private IpInfo.DataBean ipData;
    private int requestProxyType;
    private String iso;
    private String ipProvider;
    private String ipRule;

    private static int liaoUserIndex = 2;

    // 是否需要检测代理ip黑名单
    private boolean isCheckBlacklist = false;

    public ProxyUtil(String mcc, String mnc, String languate, String requestProxyType, String iso) {
        this.mcc = mcc;
        this.mnc = mnc;
        this.language = languate;
        this.requestProxyType = Integer.parseInt(requestProxyType);
        this.iso = iso;
    }

    public ProxyUtil(String iso, String ipProvider, String ipRule, String uuid) {
        this.iso = iso;
        this.ipProvider = ipProvider;
        this.ipRule = ipRule;
        this.requestProxyType = 5;
    }

    public ProxyUtil(String iso, String ipProvider, String ipRule, Boolean isCheckBlacklist) {
        this.iso = iso;
        this.ipProvider = ipProvider;
        this.ipRule = ipRule;
        this.requestProxyType = 5;
        this.isCheckBlacklist = isCheckBlacklist;
    }

    //0不需要代理;1 websocket推送过来的ip;2 http主动获取代理;3 使用rola动态住宅IP; 4 使用rola 动态机房IP; 5 老L IP。
    public IpInfo.DataBean getIp(String uuid) {
        if (requestProxyType == 0) {
            ipData = null;
        } else if (requestProxyType == 2) {
            ipData = getIpByMCC();
        } else if (requestProxyType == 3) {
            ipData = getIpConstant();
        } else if (requestProxyType == 4) {
            ipData = getIpConstantDC();
        } else if (requestProxyType == 5) {
            ipData = getIpByIso(uuid);
        }
        return ipData;
    }

    public IpInfo.DataBean getIpByTask() {
        Map header = new HashMap<String, String>();
        header.put("Accept", "application/json");
        header.put("Content-Type", "application/json");
        String rqInfo = genIpRqInfo(
                67
                , 24
                , this.mcc
                , 0
                , ""
                , "",
                "");
        String proxyStr = null;
        for (int i = 0; i < 30; i++) {
            proxyStr = Downloader.doDownload("http://wa-business.union169.com/api/ip/getIp", "POST", rqInfo, header);
            if (!TextUtils.isEmpty(proxyStr)) {
                IpInfo ipInfo = new Gson().fromJson(proxyStr, IpInfo.class);
                if (ipInfo.getCode() == 0) {
                    return ipInfo.getData();
                }
            } else {
                try {
                    Thread.sleep(3 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                continue;
            }
        }
        return null;
    }

    public IpInfo.DataBean getIpByMCC() {
        return getIpByMCC(this.mcc);
    }

    public IpInfo.DataBean getIpData() {
        return ipData;
    }

    public static IpInfo.DataBean getIpByMCC(String mcc) {
        String rqInfo = genIpByMCCRqInfo(
                mcc
                , -1
                , ""
                , "",
                "");
        Map header = new HashMap<String, String>();
        header.put("Accept", "application/json");
        header.put("Content-Type", "application/json");
        String proxyStr = null;
        for (int i = 0; i < 30; i++) {
            proxyStr = Downloader.doDownload("http://wa-business.union169.com/api/ip/getIpByMcc" + rqInfo, "POST", "", header);
//            proxyStr = Downloader.doDownload("http://wa-business.union169.com/api/ip/getIpByMcc?mcc=452&ipProvider=13","POST","",header);
            if (!TextUtils.isEmpty(proxyStr)) {
                IpInfo ipInfo = new Gson().fromJson(proxyStr, IpInfo.class);
                if (ipInfo.getCode() == 0) {
                    return ipInfo.getData();
                }
            } else {
                try {
                    Thread.sleep(3 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                continue;
            }
        }
        return null;
    }

    public static String genIpRqInfo(int taskId, int taskType, String mcc, int channelId, String ip, String androidId, String city) {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("taskId", taskId);
            jsonObject.put("taskType", taskType);
            jsonObject.put("mcc", mcc);
            jsonObject.put("channelId", channelId);
            jsonObject.put("ip", ip);
            jsonObject.put("androidId", androidId);
            jsonObject.put("city", city);
//            jsonObject.put("ipProvider","11");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return jsonObject.toString();
    }

    public static String genIpByMCCRqInfo(String mcc, int channelId, String ip, String androidId, String city) {
        StringBuffer paramSbf = new StringBuffer();
        paramSbf.append("?mcc=").append(mcc)
                .append("&channelId=").append(channelId)
                .append("&ip=").append(ip)
                .append("&androidId=").append(androidId)
                .append("&ipProvider=13")
                .append("&city=").append(city);//.append("&ipProvider=3")
        return paramSbf.toString();
    }

    public IpInfo.DataBean getIpConstant() {
        String language = this.language;
        String iso = this.iso;
        if (TextUtils.isEmpty(iso)) {
            if (language != null) {
                String[] sps = language.split("-");
                if (sps.length == 2) {
                    iso = sps[1];
                }
            }
        }
        if (iso.isEmpty()) {
            iso = "us";
        }

        String proxyIp = "gate3.rola.info";
        int proxyPort = 2143;
        String userName = "huang222_" + RandomUtil.getRange(1, 10000) + "-" + iso;
        LogUtil.log("userName:" + userName);
        String userPassword = "yzc.2020";
//        Authenticator.setDefault(new Authenticator(){
//            private PasswordAuthentication authentication = new PasswordAuthentication(userName, userPassword.toCharArray());
//            protected  PasswordAuthentication  getPasswordAuthentication(){
//                LogUtil.log("auth:"+getRequestingHost());
//                return authentication;
//            }
//        });
        IpInfo.DataBean dataBean = new IpInfo.DataBean();
        dataBean.setIp("127.0.0.1");
        dataBean.setProxyIp(proxyIp);
        dataBean.setProxyPort(proxyPort);
        dataBean.setUsername(userName);
        dataBean.setPassword(userPassword);
        dataBean.setProxyType(1);
        dataBean.setNetworkType("1");
        dataBean.setNetworkSubtype("1");
        dataBean.setNetworkOperator(this.mcc + this.mnc);
        dataBean.setNetworkOperatorName("");
        dataBean.setCity("");
        dataBean.setChannelId(-1);
        dataBean.setAndroidId("");
        dataBean.setProvider("");
        dataBean.setIso("");
        dataBean.setMcc(this.mcc);
        dataBean.setMnc(this.mnc);
        return dataBean;
    }

    public IpInfo.DataBean getIpConstantDC() {
        String language = this.language;
        String iso = this.iso;
        if (TextUtils.isEmpty(iso)) {
            if (language != null) {
                String[] sps = language.split("-");
                if (sps.length == 2) {
                    iso = sps[1];
                }
            }
        }
        if (iso.isEmpty()) {
            iso = "us";
        }
        String proxyIp = "gate3.rola.info";
        int proxyPort = 2143;
        String userName = "huang222_dc_" + RandomUtil.getRange(1, 10000) + "-" + iso;
        LogUtil.log("userName:" + userName);
        String userPassword = "yzc.2020";
//        Authenticator.setDefault(new Authenticator(){
//            private PasswordAuthentication authentication = new PasswordAuthentication(userName, userPassword.toCharArray());
//            protected  PasswordAuthentication  getPasswordAuthentication(){
//                LogUtil.log("auth:"+getRequestingHost());
//                return authentication;
//            }
//        });
        IpInfo.DataBean dataBean = new IpInfo.DataBean();
        dataBean.setIp("127.0.0.1");
        dataBean.setProxyIp(proxyIp);
        dataBean.setProxyPort(proxyPort);
        dataBean.setUsername(userName);
        dataBean.setPassword(userPassword);
        dataBean.setProxyType(1);
        dataBean.setNetworkType("1");
        dataBean.setNetworkSubtype("1");
        dataBean.setNetworkOperator(this.mcc + this.mnc);
        dataBean.setNetworkOperatorName("");
        dataBean.setCity("");
        dataBean.setChannelId(-1);
        dataBean.setAndroidId("");
        dataBean.setProvider("");
        dataBean.setIso("");
        dataBean.setMcc(this.mcc);
        dataBean.setMnc(this.mnc);
        return dataBean;
    }

    public IpInfo.DataBean getIpByIso(String uuid) {
        Map<String, String> header = new HashMap<>();
        header.put("Accept", "application/json");
        header.put("Content-Type", "application/json");
        String proxyStr = null;

        StringBuffer getProxyUrl = new StringBuffer(Constant.BASE_IP_URL);

        if (!isNumeric(this.ipProvider)) {
            // 通过代理商账号，如：h5_site_51
            getProxyUrl.append("/api/ip/h5/getIpByIso?")
                    .append("username=").append(this.ipProvider)
                    .append("&iso=").append(this.iso);
            LogUtil.logApp("ProxyInfo", "getProxyUrl:" + getProxyUrl);
        } else {
            // 通过代理商代号，如：14
            getProxyUrl.append("/api/ip/getIpByIso?")
                    .append("iso=").append(this.iso)
                    .append("&ipProvider=").append(this.ipProvider)
                    .append("&ipRule=").append(URLEncoder.encode(this.ipRule))
                    .append("&ping=").append("false");
        }
        LogUtil.logApp("getIpByIso", "uuid:" + uuid + "，获取代理URL：" + getProxyUrl);

        for (int i = 0; i < 5; i++) {
            proxyStr = Downloader.doDownload(getProxyUrl.toString(), "POST", "", header);
            LogUtil.logApp("getIpByIso", "uuid:" + uuid + ", proxy plain:" + proxyStr);

            if (TextUtils.isEmpty(proxyStr)) {
                try {
                    Thread.sleep(3 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                continue;
            }

            IpInfo ipInfo = new Gson().fromJson(proxyStr, IpInfo.class);
            if (ipInfo.getCode() == 0) {
                // 验证代理地区是否一致、IP是否黑名单
                if (verifyProxyValidity(uuid, this.iso, ipInfo.getData())) {
                    return ipInfo.getData();
                }
            }
        }
        return null;
    }

    public static boolean isNumeric(String s) {
        if (s != null && !s.trim().isEmpty()) {
            return s.matches("^[0-9]*$");
        }
        return false;
    }

    public static Proxy createProxy(IpInfo.DataBean ipData) {
        if (ipData == null) {
            return null;
        }

        System.out.println("Create proxy...");
        LogUtil.log("proxyIp:" + ipData.getProxyIp());
        LogUtil.log("proxyPort:" + ipData.getProxyPort());
        LogUtil.log("ip:" + ipData.getIp());
        LogUtil.log("proxy_username:" + ipData.getUsername());
        LogUtil.log("proxy_password:" + ipData.getPassword());
        LogUtil.log("proxyType:" + ipData.getProxyType());
        LogUtil.log("networkOperatorName:" + ipData.getNetworkOperatorName());
        LogUtil.log("provider:" + ipData.getProvider());

        final String userName = ipData.getUsername();
        final String userPassword = ipData.getPassword();
        Proxy proxy = new Proxy(ipData.getProxyType() == 1 ? Proxy.Type.SOCKS : Proxy.Type.HTTP, new InetSocketAddress(ipData.getProxyIp(), ipData.getProxyPort()));

        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                LogUtil.log("auth:" + getRequestingHost());
                return new PasswordAuthentication(userName, userPassword.toCharArray());
            }
        });

        return proxy;
    }

    public static Proxy createProxy(String uuid, IpInfo.DataBean ipData) {
        if (ipData == null) {
            return null;
        }

        String proxyMsg = "Proxy Info..."
                + ", uuid:" + uuid
                + ", proxy_iso:" + ipData.getIso()
                + ", proxyId:" + ipData.getProxyIp()
                + ", proxyPort:" + ipData.getProxyPort()
                + ", ip:" + ipData.getIp()
                + ", proxy_username:" + ipData.getUsername()
                + ", proxy_password:" + ipData.getPassword()
                + ", proxyType:" + ipData.getProxyType()
                + ", networkOperatorName:" + ipData.getNetworkOperatorName()
                + ", provider:" + ipData.getProvider();
        LogUtil.logApp("CreateProxy", proxyMsg);

        final String userName = ipData.getUsername();
        final String userPassword = ipData.getPassword();
        Proxy proxy = new Proxy(ipData.getProxyType() == 1 ? Proxy.Type.SOCKS : Proxy.Type.HTTP, new InetSocketAddress(ipData.getProxyIp(), ipData.getProxyPort()));

        // 多线程设置代理会有冲突，该种方式是设置全局代理，并不是每个线程独享一个代理
        // @link https://www.aneasystone.com/archives/2016/03/java-and-http-authentication.html
        // 改成CloseableHttpClient，单线程设置代理，每个线程独享一个代理
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                LogUtil.log("auth:" + getRequestingHost());
                return new PasswordAuthentication(userName, userPassword.toCharArray());
            }
        });

        return proxy;
    }

    public boolean verifyProxyValidity(String uuid, String taskIso, IpInfo.DataBean ipData) {
        String ipInfo = "";
        CloseableHttpResponse response = null;

        try {
            // TODO 2025/3/27 kkoip的TR代理试过在这里卡死，一直不返回响应，设置了超时但没起作用。有空再看看啥情况
            response = HttpClientUtil.doGet(Constant.VERIFY_PROXY_IPINFO_URL, null, null, ipData);
            // 1.通过ipinfo解析代理，获取信息：国家ISO、IP地址等
            ipInfo = HttpClientUtil.getEntity(response);
            if (TextUtils.isEmpty(ipInfo)) {
                // ipinfo请求失效，再次请求lumtest获取信息
                LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", ipinfo代理解析结果为空");
                CloseableHttpResponse lumtestResponse = HttpClientUtil.doGet(Constant.VERIFY_PROXY_LUMTEST_URL, null, null, ipData);
                ipInfo = HttpClientUtil.getEntity(lumtestResponse);
                if (TextUtils.isEmpty(ipInfo)) {
                    return false;
                }
            }

            cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(ipInfo);
            String country = (String) jsonObject.getOrDefault("country", "");
            String ip = (String) jsonObject.getOrDefault("ip", "");
            if (ip == null) {
                ip = "";
            }

            // 2.查询IP是否被拉黑
            if (isCheckBlacklist && isBlackIp(uuid, ip)) {
                return false;
            }

            // 3.当国家ISO为空时，使用 lumtest 再次解析代理
            if ("".equals(country)) {
                LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", ipinfo获取地区失败，使用lumtest再次获取地区信息...");
                CloseableHttpResponse lumtestResponse = HttpClientUtil.doGet(Constant.VERIFY_PROXY_LUMTEST_URL, null, null, ipData);
                ipInfo = HttpClientUtil.getEntity(lumtestResponse);
                LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", lumtest代理解析结果：" + ipInfo);
                cn.hutool.json.JSONObject lumtestJson = JSONUtil.parseObj(ipInfo);
                country = (String) lumtestJson.getOrDefault("country", "");
            }

            // 4.当国家ISO相同时，设置ip和国家ISO
            if (country.equalsIgnoreCase(taskIso)) {
                ipData.setIp(ip);
                ipData.setIso(country);
                LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", 代理IP地区与任务ISO一致：" + country + ", 解析ip：" + ip);
                return true;
            } else {
                LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", 代理IP地区与任务ISO不一致：" + country + ", 准备重新获取代理");
            }
        } catch (Exception e) {
            LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", ipinfo代理IP解析异常：" + ipInfo);
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    LogUtil.logApp("verifyProxyValidity", "uuid:" + uuid + ", http client关闭异常");
                }
            }
        }

        return false;
    }

    /**
     * 判断IP是否被拉黑
     *
     * @param ip ip地址
     * @return ip是否被拉黑
     */
    public boolean isBlackIp(String uuid, String ip) {
        if (ip == null || ip.isEmpty()) {
            LogUtil.logApp("isBlackIp", "uuid:" + uuid + ", ip为空");
            return false;
        }

        String url = Constant.VERIFY_IP_BLACKLIST + ip;
        // 0：未拉黑    1：已拉黑
        String result = Downloader.doDownload(url, "GET", null, null);
        if ("1".equals(result)) {
            LogUtil.logApp("isBlackIp", "uuid:" + uuid + ", ip已被拉黑：" + ip);
            return true;
        }

        LogUtil.logApp("isBlackIp", "uuid:" + uuid + ", 未被拉黑，正常ip：" + ip);

        return false;
    }
}
